﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MMessaging.MessagingEx.Common;
using System.Threading;

namespace MMessaging.MessagingEx.Queues
{
	/// <summary>
	/// Repräsentiert einen Channel für bidirektionale Kommunikation.
	/// Wird mit den Interfaces von zwei unidirktionalen Channels initialisiert.
	/// Definiert von sich aus nicht die Technologie der Kommunikation.
	/// </summary>
	/// <typeparam name="MESSAGETYPE"></typeparam>
	public class MChannelDuplex<MESSAGETYPE> : IMChannelDuplex<MESSAGETYPE>
		where MESSAGETYPE : class
	{
		private class ChannelEndDuplex : IMChannelEndDuplex<MESSAGETYPE>
		{
			private IMChannelEndIn<MESSAGETYPE> input;
			private IMChannelEndOut<MESSAGETYPE> output;

			public ChannelEndDuplex(
				string name,
				IMChannelEndIn<MESSAGETYPE> input,
				IMChannelEndOut<MESSAGETYPE> output
				)
			{
				Name = name;
				this.input = input;
				this.output = output;
			}

			MESSAGETYPE IMChannelEndOut<MESSAGETYPE>.WaitForMessage(int timeout)
			{
				return output.WaitForMessage(timeout);
			}

			void  IMChannelEndIn<MESSAGETYPE>.PostMessage(MESSAGETYPE message)
			{
#				if DEBUG
				bool stepover = 1 > 0;
				if (!stepover)
				{
					// #####################################################################
					// Die Verarbeitung der Message kann im Debugger weiterverfolgt werden,
					// obwohl sie gleich den Thread wechselt. Hierzu einfach den Cursor auf
					// die direkt folgende Codezeile setzen und CTRL+SHIFT+F10 drücken und anschließend 
					// F5 drücken.
					// Beachten, dass Breakpoints an den Codezeilen mit dem Tag ZVDZJHFESJ
					// gesetzt sein müssen.
					// #####################################################################
					var debuggableMsg = message as IMDebugableMessage;
					// #####################################################################

					if (debuggableMsg != null)
						debuggableMsg.Break = true;
				}
#				else
#				endif
				input.PostMessage(message);
			}

			public string Name { get; private set; }

			public WaitHandle[] WaitSignals
			{
				get
				{
					return output.WaitSignals;
				}
			}
		}

		/// <summary>
		/// Seite A des Duplex-Channels
		/// </summary>
		public IMChannelEndDuplex<MESSAGETYPE> ChannelEndLeft { get; private set; }
		/// <summary>
		/// Seite B des Duplex-Channels
		/// </summary>
		public IMChannelEndDuplex<MESSAGETYPE> ChannelEndRight { get; private set; }

		/// <summary>
		/// Konstruktor
		/// </summary>
		/// <param name="name">
		/// Logging-Name des Channels
		/// </param>
		/// <param name="simplexChannel1">
		/// Ein unidirektionaler Channel
		/// </param>
		/// <param name="simplexChannel2">
		/// Ein anderer unidirektionaler Channel für die andere Richtung
		/// </param>
		public MChannelDuplex(
			string name,
			IMChannel<MESSAGETYPE> simplexChannel1,
			IMChannel<MESSAGETYPE> simplexChannel2
			)
		{
			ChannelEndLeft = new ChannelEndDuplex(name,simplexChannel1,simplexChannel2);
			ChannelEndRight = new ChannelEndDuplex(name, simplexChannel2, simplexChannel1);
		}
	}
}
